﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace GPExplorer{
    /// <summary>
    /// The Main Form For GPExplorer
    /// </summary>
    public partial class FrmMain : Form{
        //This is used for a unique list of artists
        private List<string> _artists;
        //This contains a list of each ListView and its containing TabPage
        private readonly Dictionary<TabPage, DataGridView> _views;

        private DirectoryInfo _folderName;
        private string _libName;

        /// <summary>
        /// Initializes a new instance of the <see cref="FrmMain"/> class.
        /// </summary>
        public FrmMain(){
            InitializeComponent();

            if (!File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\GPExplorer\Tab.db3")){
                Database.CreateTabTableDatabase();
                Database.CreateTabsTable();
            }

            recentsToolStripMenuItem1.UpdateList();
            GpFiles = new List<GpFile>();
            
            DgvFavorites.DoubleClick += GridView_DoubleClick;
            _views = new Dictionary<TabPage, DataGridView>{{TabSongsLists.TabPages[0], DgvFavorites}};
            _artists = new List<string>();
            LoadFavorites();
            LoadLibraries();
        }

        /// <summary>
        /// Gets or sets the Libraries GP tab files.
        /// </summary>
        /// <value>
        /// The Guitar Pro Tab files.
        /// </value>
        public ICollection<GpFile> GpFiles { get; set; }

        /// <summary>
        /// Gets or sets the PTB files.
        /// </summary>
        /// <value>
        /// The PTB files.
        /// </value>
        public ICollection<PtbFile> PtbFiles { get; set; }

        private void LoadLibraries(){
            ICollection<string> _libs = Database.GetLibrariesDistinct();

            foreach (string _lib in _libs){
                LstLibraries.Items.Add(_lib);
            }
        }

        /// <summary>
        /// Loads the favorites.
        /// </summary>
        private void LoadFavorites(){
            _libName = "Favorites";
            List<GpFile> _favs = Database.GetGpTabsFromLibrary("Favorites");

            List<string> _art = new List<string>();
            if (_favs == null) return;
            int _i = 0;
            foreach (GpFile _gp in _favs) {
                object[] _row = { Path.GetFileNameWithoutExtension(_gp.FilePath), _gp.Artist, _gp.SongName, _gp.Version, _gp.FileDate };

                DgvFavorites.Rows.Add(_row);
                DgvFavorites.Rows[_i].Tag = _gp.FilePath;
                _art.Add(_gp.Artist);
                _i++;

            }

            IList<string> _aList = _art.Distinct().OrderBy(q => q).ToList();
            foreach (string _artist in _aList){
                CboArtists.Items.Add(_artist);
            }
            CboArtists.SelectedIndex = 0;

            LblCount.Text = _favs.Count + @" files";
        }

        /// <summary>
        /// Handles the Click event of the openToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void openToolStripMenuItem_Click(object sender, EventArgs e){
            OpenFileDialog _ofd = new OpenFileDialog{Filter = @"Guitar Pro Files (.gp*)|*.gp*|PowerTab Files (.ptb)|*.ptb"};
            if (_ofd.ShowDialog() == DialogResult.OK){
                Process.Start(_ofd.FileName);
            }
        }

        /// <summary>
        /// Walks the directory tree.
        /// </summary>
        /// <param name="root">The root of the directory.</param>
        private void WalkDirectoryTree(DirectoryInfo root){
            FileInfo[] _gpFiles = null;
            FileInfo[] _ptbFiles = null;

            // First, process all the files directly under this folder
            try{
                _gpFiles = root.GetFiles("*.gp*");
                _ptbFiles = root.GetFiles("*.ptb");
            }
                // This is thrown if even one of the files requires permissions greater
                // than the application provides.
            catch (UnauthorizedAccessException){
            }

            catch (DirectoryNotFoundException _e){
                Console.WriteLine(_e.Message);
            }

            if (_gpFiles == null && _ptbFiles == null) return;
            foreach (FileInfo _fi in _gpFiles){
                GpFile _gp = new GpFile();
                _gp.GetGpFile(_fi.FullName, _gp);
                GpFiles.Add(_gp);
            }

            foreach (FileInfo _file in _ptbFiles){
                PtbFile _ptb = new PtbFile();
                _ptb.GetPtbFile(_file.FullName, _ptb);
                PtbFiles.Add(_ptb);
            }


            // Now find all the subdirectories under this directory.
            DirectoryInfo[] _subDirs = root.GetDirectories();

            foreach (DirectoryInfo _dirInfo in _subDirs){
                // Recursive call for each subdirectory.
                WalkDirectoryTree(_dirInfo);
            }
        }

        /// <summary>
        /// Displays the GPFiles in the DataGridView.
        /// </summary>
        /// <param name="gridView">The <see cref="DataGridView"/>.</param>
        private void DisplayInGridView(DataGridView gridView){
            gridView.Rows.Clear();
            GpFiles = Database.GetGpTabsFromLibrary(_libName);
            PtbFiles = Database.GetPtbTabsFromLibrary((_libName));
            
            //Add Guitar Pro Files
            int _i = 0;
            foreach (GpFile _gp in GpFiles){
                    object[] _row = { Path.GetFileNameWithoutExtension(_gp.FilePath), _gp.Artist, _gp.SongName, _gp.Version, _gp.FileDate };
                gridView.Rows.Add(_row);
                gridView.Rows[_i].Tag = _gp.FilePath;
                _i++;
            }

            //Add PowerTab Files
            
            foreach (PtbFile _ptb in PtbFiles) {
                object[] _row = { Path.GetFileNameWithoutExtension(_ptb.FilePath), _ptb.Artist, _ptb.SongName, _ptb.Version, _ptb.FileDate };
                gridView.Rows.Add(_row);
                gridView.Rows[_i].Tag = _ptb.FilePath;
                _i++;
            }


            IList<string> _aList = _artists.Distinct().OrderBy(q => q).ToList();
            gridView.Tag = _aList;
            GpFiles.Clear();
            PtbFiles.Clear();
        }

        private void GridView_DoubleClick(object sender, EventArgs e){
            if (((DataGridView) sender).SelectedRows.Count > 0){
                Process.Start(((DataGridView) sender).SelectedRows[0].Tag.ToString());
            }
        }


        /// <summary>
        /// Handles the Click event of the newToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void newToolStripMenuItem_Click(object sender, EventArgs e){
            GpFiles.Clear();
            PtbFiles.Clear();

            //get the root of the folder to browse
            if (_folderName == null){
                FolderBrowserDialog _fbd = new FolderBrowserDialog();
                
                DialogResult _result = _fbd.ShowDialog();
                if (_result == DialogResult.OK && _fbd.SelectedPath != string.Empty){
                    _folderName = new DirectoryInfo(_fbd.SelectedPath);
                }
            }

            //Get the library name
            FrmName _name = new FrmName();
            _name.ShowDialog();
            if (_name.DialogResult == DialogResult.OK && _folderName != null){
                //Get the files
                WalkDirectoryTree(_folderName);
                //Database.InsertTab(new GpFile(), _name.LibraryName);
                //Database.InsertTab(new PtbFile(), _name.LibraryName);
                if (_name.LibraryName == null){
                    return;
                }
                //LstLibraries.Items.Add(_name.LibraryName);
            }
            else{
                return;
            }

            //Insert into db
            InsertTabs(_name);

            //Add the tab Page with the new ListView
            DataGridView _list = AddTabPage(_name.LibraryName);
            _libName = _name.LibraryName;

            //load files into new ListView
            DisplayInGridView(_list);

            recentsToolStripMenuItem1.AddRecentItem(_name.LibraryName);
            LstLibraries.Items.Add(_name.LibraryName);
            _folderName = null;
        }

        private void InsertTabs(FrmName name){
            toolStripProgressBar1.Minimum = 0;
            toolStripProgressBar1.Step = 1;
            toolStripProgressBar1.Maximum = GpFiles.Count + PtbFiles.Count;
            foreach (GpFile _file in GpFiles){
                toolStripProgressBar1.PerformStep();
                Database.InsertTab(_file, name.LibraryName);
            }
            foreach (PtbFile _f in PtbFiles) {
                toolStripProgressBar1.PerformStep();
                Database.InsertTab(_f, name.LibraryName);
            }
            toolStripProgressBar1.Value = 0;
        }


        /// <summary>
        ///     Adds a new tab page that will contain the new DataGridView.
        /// </summary>
        /// <param name="folderName">Name of the folder.</param>
        /// <returns>the libraries <see cref="DataGridView" /></returns>
        private DataGridView AddTabPage(string folderName){
            TabPage _page = new TabPage{
                Text = folderName,
                Dock = DockStyle.Fill,
                ContextMenuStrip = CtxSong
            };

            TabSongsLists.TabPages.Add(_page);
            DataGridView _dgView = CreateGridView();
            _views.Add(_page, _dgView);
            _page.Controls.Add(_dgView);
            _page.BringToFront();
            return _dgView;
        }

        /// <summary>
        ///     Creates the ListView for the library.
        /// </summary>
        /// <returns>the new <see cref="DataGridView" /></returns>
        private DataGridView CreateGridView(){
            DataGridView _dgView = new DataGridView{
                BackColor = Color.White,
                Dock = DockStyle.Fill,
                EditMode = DataGridViewEditMode.EditProgrammatically,
                RowHeadersVisible = false,
                SelectionMode = DataGridViewSelectionMode.FullRowSelect,
                AlternatingRowsDefaultCellStyle ={BackColor = Color.Wheat},
                ColumnHeadersDefaultCellStyle ={Alignment = DataGridViewContentAlignment.MiddleCenter}
            };
            _dgView.DoubleClick += GridView_DoubleClick;
            
         

            DataGridViewColumn _col1 = new DataGridViewTextBoxColumn {
                HeaderText  = @"File Name",
                Width = 250
            };
            DataGridViewColumn _col2 = new DataGridViewTextBoxColumn {
                HeaderText = @"Artist",
                Width = 200
            };
            DataGridViewColumn _col3 = new DataGridViewTextBoxColumn {
                HeaderText = @"Song",
                Width = 200
            };
            DataGridViewColumn _col4 = new DataGridViewTextBoxColumn {
                HeaderText = @"Version",
                Width = 60
            };
            DataGridViewColumn _col5 = new DataGridViewTextBoxColumn {
                HeaderText = @"Date",
                Width = 200
            };
            _dgView.Columns.Add(_col1);
            _dgView.Columns.Add(_col2);
            _dgView.Columns.Add(_col3);
            _dgView.Columns.Add(_col4);
            _dgView.Columns.Add(_col5);

            return _dgView;
        }

        /// <summary>
        ///     Handles the Click event of the addToFavoritesToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        /// <remarks>This basically gets the file path of the desired file and serializes it to the "Favorites.lib" file</remarks>
        private void addToFavoritesToolStripMenuItem_Click(object sender, EventArgs e){
            GpFile _file = new GpFile();
            
            //Currently Selected DataGridView
            DataGridView _lv = _views[TabSongsLists.SelectedTab];

            if (_lv == null) return;
            
            //Add the favorite to the DataGridView
            foreach (DataGridViewRow _item in _lv.SelectedRows){
                _file.GetGpFile(_item.Tag.ToString(), _file);
                AddFavorite(_file);
            }
            //insert new favorite into database
           // foreach (DataGridViewRow _gi in DgvFavorites.Rows){
                GpFile _gp = new GpFile();
                _gp.GetGpFile(_file.FilePath, _gp);

                Database.InsertTab(_gp, "Favorites");
            //}
            _libName = "Favorites";
        }

        /// <summary>
        ///     Adds the new favorite item to the Favorites tabs' ListView .
        /// </summary>
        /// <param name="favorite">The desired favorite.</param>
        private void AddFavorite(GpFile favorite){
            object[] _row = { Path.GetFileNameWithoutExtension(favorite.FilePath), favorite.Artist, favorite.SongName, favorite.Version, favorite.FileDate };

            DgvFavorites.Rows.Add(_row);
            DgvFavorites.Rows[DgvFavorites.Rows.Count - 1].Selected = true;
            if (DgvFavorites.CurrentRow != null)
                DgvFavorites.Rows[DgvFavorites.CurrentRow.Index].Tag = favorite.FilePath;
        }

        /// <summary>
        ///     Handles the ItemClick event of the recentsToolStripMenuItem1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        private void recentsToolStripMenuItem1_ItemClick(object sender, EventArgs e){
            _libName = ((ToolStripMenuItem) sender).Text;
            DataGridView _list = AddTabPage(((ToolStripMenuItem) sender).Text);
            DisplayInGridView(_list);
        }

        /// <summary>
        ///     Handles the Click event of the removeFromFavoritesToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        /// <remarks>re-serializes the "Favorites.lib" file</remarks>
        private void removeFromFavoritesToolStripMenuItem_Click(object sender, EventArgs e){
            GpFile _gp = new GpFile();
            DataGridViewSelectedRowCollection _itemCollection = DgvFavorites.SelectedRows;
            foreach (DataGridViewRow _item in _itemCollection){
                DgvFavorites.Rows.RemoveAt(_item.Index);
                Database.DeleteTabFromLibrary(_gp.GetGpFile(_item.Tag.ToString(), _gp), "Favorites");
            }
        }

        /// <summary>
        ///     Handles the Click event of the closeTabToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        private void closeTabToolStripMenuItem_Click(object sender, EventArgs e){
            if (TabSongsLists.SelectedTab == TabFavorites){
                return;
            }
            TabSongsLists.TabPages.Remove(TabSongsLists.SelectedTab);
            //Remove it from the dictionary
            _views.Remove(TabSongsLists.SelectedTab);
        }

        /// <summary>
        ///     Handles the SelectedIndexChanged event of the TabSongsLists control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        private void TabSongsLists_SelectedIndexChanged(object sender, EventArgs e){
            _artists.Clear();
            //This little loop is my attempt to clear the artists listbox. the items.Clear method wasn't working
            while (CboArtists.Items.Count > 0){
                CboArtists.Items.RemoveAt(0);
            }
            _libName = TabSongsLists.SelectedTab.Text;
            CboArtists.Items.Insert(0, "(All)");
            CboArtists.SelectedIndex = 0;

            _artists = Database.GetLibrariesArtistsDistinct(_libName);

            foreach (string _art in _artists){
                CboArtists.Items.Add(_art);
            }

            LblCount.Text = (_views[TabSongsLists.SelectedTab].Rows.Count) + @" files";
        }

        /// <summary>
        ///     Handles the SelectedIndexChanged event of the LstArtists control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        private void CboArtists_SelectedIndexChanged(object sender, EventArgs e){
            if (CboArtists.SelectedItem == null) return;
            if (CboArtists.SelectedItem.ToString() == "(All)"){
                DisplayInGridView(_views[TabSongsLists.SelectedTab]);
            }
            else{
                ICollection<GpFile> _list = Database.GetSongsByArtist(CboArtists.SelectedItem.ToString(), _libName);
                FilterListView(_list);
            }
        }

        /// <summary>
        ///     Filters the ListView.
        /// </summary>
        /// <param name="list">The list of GPFiles.</param>
        private void FilterListView(IEnumerable<GpFile> list){
            IEnumerable<GpFile> _results = list.Where(c => c.Artist == CboArtists.SelectedItem.ToString());
            DataGridView _gridView = _views[TabSongsLists.SelectedTab];
            _gridView.Rows.Clear();
            int _i = 0;
            foreach (GpFile _gp in _results){
                object[] _row = { Path.GetFileNameWithoutExtension(_gp.FilePath), _gp.Artist, _gp.SongName, _gp.Version, _gp.FileDate };
                _gridView.Rows.Add(_row);
                _gridView.Rows[_i].Tag = _gp.FilePath;
                _i++;
            }
        }

        /// <summary>
        /// Handles the DoubleClick event of the LstLibraries control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void LstLibraries_DoubleClick(object sender, EventArgs e){
            _libName = ((ListBox) sender).SelectedItem.ToString();
            DataGridView _list = AddTabPage(((ListBox) sender).SelectedItem.ToString());
            DisplayInGridView(_list);
        }

        /// <summary>
        /// Handles the Click event of the deleteLibraryToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void deleteLibraryToolStripMenuItem_Click(object sender, EventArgs e){
            Database.DeleteLibrary(LstLibraries.SelectedItem.ToString());

            TabSongsLists.TabPages.RemoveByKey(LstLibraries.SelectedItem.ToString());
            recentsToolStripMenuItem1.RemoveRecentItem(LstLibraries.SelectedItem.ToString());
            LstLibraries.Items.Remove(LstLibraries.SelectedItem.ToString());
            }

        /// <summary>
        /// Handles the Opening event of the CtxLibraries control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="CancelEventArgs"/> instance containing the event data.</param>
        private void CtxLibraries_Opening(object sender, CancelEventArgs e){
            deleteLibraryToolStripMenuItem.Enabled = LstLibraries.SelectedItems.Count != 0;
        }

        /// <summary>
        /// Handles the Click event of the addToLibraryToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void addToLibraryToolStripMenuItem_Click(object sender, EventArgs e) {
            FrmLibraries _libs = new FrmLibraries();
            if (_libs.ShowDialog() != DialogResult.OK || _libs.Library == string.Empty) return;

            DataGridView _lv;
            GpFile _file = new GpFile();

            _views.TryGetValue(TabSongsLists.SelectedTab, out _lv);
            if (_lv == null){
                return;}
            _file.FilePath = _lv.SelectedRows[0].Tag.ToString();
            _file.SongName = _lv.SelectedRows[0].Cells[2].Value.ToString();
            _file.Artist = _lv.SelectedRows[0].Cells[1].Value.ToString();
            _file.Version = _lv.SelectedRows[0].Cells[3].Value.ToString();
            _file.FileDate = _lv.SelectedRows[0].Cells[4].Value.ToString();

            Database.InsertTab(_file,_libs.Library);
        }

        /// <summary>
        /// Handles the Click event of the removeFromLibraryToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void removeFromLibraryToolStripMenuItem_Click(object sender, EventArgs e) {
            DataGridView _lv;
            GpFile _file = new GpFile();
            _views.TryGetValue(TabSongsLists.SelectedTab, out _lv);
            if (_lv == null) return;
            _file.FilePath = _lv.SelectedRows[0].Tag.ToString();
            _file.SongName = _lv.SelectedRows[0].Cells[2].Value.ToString();
            _file.Artist = _lv.SelectedRows[0].Cells[1].Value.ToString();
            _file.Version = _lv.SelectedRows[0].Cells[3].Value.ToString();
            _file.FileDate = _lv.SelectedRows[0].Cells[4].Value.ToString();
            

            Database.DeleteTabFromLibrary(_file, TabSongsLists.SelectedTab.Text);
            try{
                foreach (DataGridViewRow _item in _lv.Rows){
                    _lv.Rows.RemoveAt(_item.Index);
                }
            }
            catch (InvalidOperationException _e){
                MessageBox.Show(_e.Message,@"Error Removing File");
            }
            _artists.Clear();
            CboArtists.Items.Remove(_file.Artist);
            _artists = Database.GetLibrariesArtistsDistinct(_libName);

            foreach (string _art in _artists) {
                CboArtists.Items.Add(_art);
                CboArtists.AutoCompleteSource = AutoCompleteSource.ListItems;
            }
        }

        /// <summary>
        /// Handles the Opening event of the CtxSong control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="CancelEventArgs"/> instance containing the event data.</param>
        private void CtxSong_Opening(object sender, CancelEventArgs e){
            addToFavoritesToolStripMenuItem.Enabled = _views[TabSongsLists.SelectedTab].Name != @"DgvFavorites";
        }

        /// <summary>
        /// Handles the Click event of the insertFileIntoLibraryToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void insertFileIntoLibraryToolStripMenuItem_Click(object sender, EventArgs e){
            OpenFileDialog _ofd = new OpenFileDialog{
                Filter = @"Guitar Pro Files (.gp*)|*.gp*|PowerTab Files (.ptb)|*.ptb"
            };
            if (_ofd.ShowDialog() != DialogResult.OK) return;
            DataGridView _dgv;
            if (_ofd.FileName.Contains("gp")){

                GpFile _gp = new GpFile();
                _gp.GetGpFile(_ofd.FileName, _gp);

                Database.InsertTab(_gp, TabSongsLists.SelectedTab.Text);
                _views.TryGetValue(TabSongsLists.SelectedTab, out _dgv);
                if (_dgv == null) {
                    return;
                }
                object[] _row = { Path.GetFileNameWithoutExtension(_gp.FilePath), _gp.Artist, _gp.SongName, _gp.Version, _gp.FileDate };
                _dgv.Rows.Add(_row);
                _dgv.Rows[_dgv.Rows.Count - 1].Tag = _gp.FilePath;
                CboArtists.Items.Add(_gp.Artist);
            }
            else{
                //insert powertab
                PtbFile _ptb = new PtbFile();
                _ptb.GetPtbFile(_ofd.FileName, _ptb);

                Database.InsertTab(_ptb, TabSongsLists.SelectedTab.Text);
                _views.TryGetValue(TabSongsLists.SelectedTab, out _dgv);
                if (_dgv == null) {
                    return;
                }
                object[] _row = { Path.GetFileNameWithoutExtension(_ptb.FilePath), _ptb.Artist, _ptb.SongName, _ptb.Version, _ptb.FileDate };
                _dgv.Rows.Add(_row);
                _dgv.Rows[_dgv.Rows.Count - 1].Tag = _ptb.FilePath;
                CboArtists.Items.Add(_ptb.Artist);
            }



        }
    }
}